#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Linux RTC (Real-Time Clock) 时间管理工具
基于 /sys/class/rtc/ 和 hwclock 命令
"""

import os
import time
import subprocess
import json
import logging
from datetime import datetime
from typing import Dict, Optional, Tuple
from dataclasses import dataclass
from enum import Enum
import glob
import re

# 设置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)



class TimeSync(Enum):
    """时间同步方向枚举"""
    SYSTEM_TO_RTC = "system_to_rtc"  # 系统时间 -> RTC
    RTC_TO_SYSTEM = "rtc_to_system"  # RTC -> 系统时间
    NONE = "none"

@dataclass
class RTCInfo:
    """RTC设备信息"""
    device: str
    name: str
    date: str
    time: str
    since_epoch: int
    datetime_obj: datetime
    timestamp: datetime

@dataclass
class TimeComparison:
    """时间比较结果"""
    system_time: datetime
    rtc_time: datetime
    difference_seconds: float
    rtc_faster: bool
    sync_needed: bool

class RTCManager:
    """RTC时间管理器"""
    
    def __init__(self):
        self.rtc_base_path = "/sys/class/rtc"
        self.rtc_devices = {}
        self.primary_rtc = "rtc0"
        
        # 时间同步阈值 (秒)
        self.sync_threshold = 2.0
        
        # 检查RTC设备
        self._detect_rtc_devices()

    def set_sys_time(self,new_time):
        #设置系统时间
        # new_time = "2022-01-01 00:00:00"
        subprocess.check_call(["date", "-s", new_time])
    
    def _detect_rtc_devices(self):
        """检测RTC设备"""
        try:
            if not os.path.exists(self.rtc_base_path):
                logger.warning(f"RTC基础路径不存在: {self.rtc_base_path}")
                return
            
            # 搜索RTC设备
            rtc_pattern = os.path.join(self.rtc_base_path, "rtc*")
            rtc_dirs = glob.glob(rtc_pattern)
            
            for rtc_dir in rtc_dirs:
                device_name = os.path.basename(rtc_dir)
                
                # 检查必要文件是否存在
                required_files = ['name', 'date', 'time', 'since_epoch']
                files_exist = all(
                    os.path.exists(os.path.join(rtc_dir, f)) 
                    for f in required_files
                )
                
                if files_exist:
                    self.rtc_devices[device_name] = rtc_dir
                    logger.info(f"检测到RTC设备: {device_name}")
                else:
                    logger.warning(f"RTC设备 {device_name} 文件不完整")
        
        except Exception as e:
            logger.error(f"检测RTC设备失败: {e}")
    
    def read_rtc_info(self, device: str = None) -> Optional[RTCInfo]:
        """
        读取RTC设备信息
        
        Args:
            device: RTC设备名称,None使用primary_rtc
            
        Returns:
            RTC信息对象
        """
        if device is None:
            device = self.primary_rtc
        
        if device not in self.rtc_devices:
            logger.error(f"RTC设备 {device} 不存在")
            return None
        
        try:
            rtc_dir = self.rtc_devices[device]
            
            # 读取设备名称
            with open(os.path.join(rtc_dir, 'name'), 'r') as f:
                name = f.read().strip()
            
            # 读取日期
            with open(os.path.join(rtc_dir, 'date'), 'r') as f:
                date = f.read().strip()
            
            # 读取时间
            with open(os.path.join(rtc_dir, 'time'), 'r') as f:
                time_str = f.read().strip()
            
            # 读取epoch秒数
            with open(os.path.join(rtc_dir, 'since_epoch'), 'r') as f:
                since_epoch = int(f.read().strip())
            
            # 创建datetime对象
            datetime_str = f"{date} {time_str}"
            datetime_obj = datetime.strptime(datetime_str, "%Y-%m-%d %H:%M:%S")
            
            return RTCInfo(
                device=device,
                name=name,
                date=date,
                time=time_str,
                since_epoch=since_epoch,
                datetime_obj=datetime_obj,
                timestamp=datetime.now()
            )
            
        except Exception as e:
            logger.error(f"读取RTC信息失败: {e}")
            return None
    
    def read_proc_rtc(self) -> Optional[Dict]:
        """
        读取 /proc/driver/rtc 详细信息
        
        Returns:
            RTC详细信息字典
        """
        proc_rtc_path = "/proc/driver/rtc"
        
        if not os.path.exists(proc_rtc_path):
            logger.warning(f"文件不存在: {proc_rtc_path}")
            return None
        
        try:
            rtc_info = {}
            
            with open(proc_rtc_path, 'r') as f:
                for line in f:
                    line = line.strip()
                    if ':' in line:
                        key, value = line.split(':', 1)
                        rtc_info[key.strip()] = value.strip()
            
            return rtc_info
            
        except Exception as e:
            logger.error(f"读取 /proc/driver/rtc 失败: {e}")
            return None
    
    def run_hwclock(self, action: str) -> Tuple[bool, str]:
        """
        执行hwclock命令
        
        Args:
            action: 操作类型 (-r, -w, -s)
            
        Returns:
            (成功标志, 输出信息)
        """
        try:
            cmd = ['hwclock', action]
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=30
            )
            
            success = result.returncode == 0
            output = result.stdout.strip() if success else result.stderr.strip()
            
            return success, output
            
        except subprocess.TimeoutExpired:
            logger.error("hwclock命令超时")
            return False, "命令超时"
        except FileNotFoundError:
            logger.error("hwclock命令不存在")
            return False, "hwclock命令不存在"
        except Exception as e:
            logger.error(f"执行hwclock失败: {e}")
            return False, str(e)
    
    def read_hwclock(self) -> Optional[datetime]:
        """
        读取硬件时钟时间
        
        Returns:
            硬件时钟时间
        """
        success, output = self.run_hwclock('-r')
        
        if not success:
            logger.error(f"读取硬件时钟失败: {output}")
            return None
        
        try:
            # 解析hwclock输出
            # 格式通常是: 2024-01-01 12:00:00.123456+08:00
            # 或者: Mon 01 Jan 2024 12:00:00 PM CST
            
            # 尝试多种格式解析
            formats = [
                "%Y-%m-%d %H:%M:%S",
                "%a %d %b %Y %I:%M:%S %p %Z",
                "%a %b %d %H:%M:%S %Y",
            ]
            
            # 清理输出字符串
            clean_output = re.sub(r'\.\d+[+-]\d{2}:\d{2}', '', output)
            clean_output = re.sub(r'\s+', ' ', clean_output).strip()
            
            for fmt in formats:
                try:
                    return datetime.strptime(clean_output, fmt)
                except ValueError:
                    continue
            
            logger.error(f"无法解析hwclock输出: {output}")
            return None
            
        except Exception as e:
            logger.error(f"解析hwclock输出失败: {e}")
            return None
    
    def sync_system_to_rtc(self) -> bool:
        """
        同步系统时间到RTC
        
        Returns:
            操作成功标志
        """
        logger.info("同步系统时间到RTC...")
        success, output = self.run_hwclock('-w')
        
        if success:
            logger.info("系统时间已同步到RTC")
        else:
            logger.error(f"同步失败: {output}")
        
        return success
    
    def sync_rtc_to_system(self) -> bool:
        """
        同步RTC时间到系统
        
        Returns:
            操作成功标志
        """
        logger.info("同步RTC时间到系统...")
        success, output = self.run_hwclock('-s')
        
        if success:
            logger.info("RTC时间已同步到系统")
        else:
            logger.error(f"同步失败: {output}")
        
        return success
    
    def compare_times(self) -> Optional[TimeComparison]:
        """
        比较系统时间和RTC时间
        
        Returns:
            时间比较结果
        """
        try:
            # 获取系统时间
            system_time = datetime.now()
            
            # 获取RTC时间
            rtc_time = self.read_hwclock()
            
            if rtc_time is None:
                logger.error("无法获取RTC时间")
                return None
            
            # 计算时间差
            diff_seconds = (rtc_time - system_time).total_seconds()
            rtc_faster = diff_seconds > 0
            sync_needed = abs(diff_seconds) > self.sync_threshold
            
            return TimeComparison(
                system_time=system_time,
                rtc_time=rtc_time,
                difference_seconds=diff_seconds,
                rtc_faster=rtc_faster,
                sync_needed=sync_needed
            )
            
        except Exception as e:
            logger.error(f"比较时间失败: {e}")
            return None
    
    def auto_sync(self, prefer_rtc: bool = False) -> bool:
        """
        自动同步时间
        
        Args:
            prefer_rtc: 是否优先使用RTC时间
            
        Returns:
            同步成功标志
        """
        comparison = self.compare_times()
        
        if not comparison:
            return False
        
        if not comparison.sync_needed:
            logger.info("时间差异在允许范围内，无需同步")
            return True
        
        logger.info(f"时间差异: {comparison.difference_seconds:.2f}秒")
        
        if prefer_rtc:
            logger.info("使用RTC时间同步系统")
            return self.sync_rtc_to_system()
        else:
            logger.info("使用系统时间同步RTC")
            return self.sync_system_to_rtc()
    
    def set_system_time(self, target_time: datetime) -> bool:
        """
        设置系统时间
        
        Args:
            target_time: 目标时间
            
        Returns:
            设置成功标志
        """
        try:
            # 格式化时间字符串
            time_str = target_time.strftime("%Y-%m-%d %H:%M:%S")
            
            # 使用date命令设置时间
            cmd = ['date', '-s', time_str]
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=10
            )
            
            success = result.returncode == 0
            
            if success:
                logger.info(f"系统时间已设置为: {time_str}")
            else:
                logger.error(f"设置系统时间失败: {result.stderr}")
            
            return success
            
        except Exception as e:
            logger.error(f"设置系统时间失败: {e}")
            return False
    
    def get_rtc_summary(self) -> Dict:
        """
        获取RTC摘要信息
        
        Returns:
            RTC摘要信息字典
        """
        summary = {
            'devices': {},
            'comparison': None,
            'proc_rtc': None,
            'timestamp': datetime.now().isoformat()
        }
        
        # 读取所有RTC设备信息
        for device_name in self.rtc_devices:
            rtc_info = self.read_rtc_info(device_name)
            if rtc_info:
                summary['devices'][device_name] = {
                    'name': rtc_info.name,
                    'date': rtc_info.date,
                    'time': rtc_info.time,
                    'since_epoch': rtc_info.since_epoch,
                    'datetime': rtc_info.datetime_obj.isoformat()
                }
        
        # 时间比较
        comparison = self.compare_times()
        if comparison:
            summary['comparison'] = {
                'system_time': comparison.system_time.isoformat(),
                'rtc_time': comparison.rtc_time.isoformat(),
                'difference_seconds': comparison.difference_seconds,
                'rtc_faster': comparison.rtc_faster,
                'sync_needed': comparison.sync_needed
            }
        
        # 读取/proc/driver/rtc信息
        proc_rtc = self.read_proc_rtc()
        if proc_rtc:
            summary['proc_rtc'] = proc_rtc
        
        return summary
    
    def export_rtc_info(self, filename: str = None):
        """
        导出RTC信息到JSON文件
        
        Args:
            filename: 导出文件名
        """
        if filename is None:
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"rtc_info_{timestamp}.json"
        
        try:
            summary = self.get_rtc_summary()
            
            with open(filename, 'w') as f:
                json.dump(summary, f, indent=2, ensure_ascii=False)
            
            logger.info(f"RTC信息已导出到: {filename}")
            
        except Exception as e:
            logger.error(f"导出RTC信息失败: {e}")
    
    def monitor_time_drift(self, duration_minutes: int = 60, check_interval: int = 60):
        """
        监控时间漂移
        
        Args:
            duration_minutes: 监控时长(分钟)
            check_interval: 检查间隔(秒)
        """
        logger.info(f"开始监控时间漂移，持续{duration_minutes}分钟")
        
        start_time = time.time()
        end_time = start_time + (duration_minutes * 60)
        
        drift_history = []
        
        try:
            while time.time() < end_time:
                comparison = self.compare_times()
                
                if comparison:
                    drift_record = {
                        'timestamp': datetime.now().isoformat(),
                        'difference_seconds': comparison.difference_seconds,
                        'rtc_faster': comparison.rtc_faster
                    }
                    
                    drift_history.append(drift_record)
                    
                    # 输出当前状态
                    status = "RTC快" if comparison.rtc_faster else "系统快"
                    logger.info(f"时间差异: {comparison.difference_seconds:.2f}秒 ({status})")
                    
                    # 检查是否需要同步
                    if comparison.sync_needed:
                        logger.warning(f"时间差异超过阈值({self.sync_threshold}秒)，建议同步")
                
                time.sleep(check_interval)
        
        except KeyboardInterrupt:
            logger.info("监控被中断")
        
        # 分析漂移数据
        if drift_history:
            differences = [record['difference_seconds'] for record in drift_history]
            
            logger.info(f"时间漂移监控完成:")
            logger.info(f"  监控次数: {len(differences)}")
            logger.info(f"  平均差异: {sum(differences)/len(differences):.2f}秒")
            logger.info(f"  最大差异: {max(differences):.2f}秒")
            logger.info(f"  最小差异: {min(differences):.2f}秒")
            
            # 导出漂移数据
            drift_file = f"time_drift_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
            try:
                with open(drift_file, 'w') as f:
                    json.dump(drift_history, f, indent=2, ensure_ascii=False)
                logger.info(f"漂移数据已导出到: {drift_file}")
            except Exception as e:
                logger.error(f"导出漂移数据失败: {e}")

    def check_ntp_sync_status(self):
        """
        检查NTP时间同步状态
        """
        try:
            # 检查sysntpd服务状态
            cmd = ['/etc/init.d/sysntpd', 'status']
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=10
            )
            
            service_running = result.returncode == 0
            
            # 检查最近的NTP日志
            cmd = ['logread']
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=10
            )
            
            ntp_logs = []
            if result.returncode == 0:
                lines = result.stdout.split('\n')
                ntp_logs = [line for line in lines if 'ntp' in line.lower()]
            
            # 检查时间是否合理（不是1970年）
            current_time = datetime.now()
            time_reasonable = current_time.year > 2020
            
            status = {
                'service_running': service_running,
                'time_reasonable': time_reasonable,
                'recent_ntp_logs': ntp_logs[-3:],  # 最近3条NTP日志
                'current_time': current_time.strftime('%Y-%m-%d %H:%M:%S')
            }
            
            logger.info(f"NTP同步状态: {status}")
            return status
            
        except Exception as e:
            logger.error(f"检查NTP状态失败: {e}")
            return None

    def fix_ntp_service(self):
        """
        修复NTP服务问题
        """
        try:
            # 停止服务
            subprocess.run(['/etc/init.d/sysntpd', 'stop'], timeout=10)
            
            # 手动同步一次
            servers = ['ntp5.aliyun.com', '0.cn.pool.ntp.org']
            for server in servers:
                try:
                    result = subprocess.run(
                        ['ntpdate', '-s', server],
                        capture_output=True,
                        text=True,
                        timeout=15
                    )
                    if result.returncode == 0:
                        logger.info(f"手动同步成功: {server}")
                        break
                except:
                    continue
            
            # 重启服务
            result = subprocess.run(
                ['/etc/init.d/sysntpd', 'restart'],
                capture_output=True,
                text=True,
                timeout=30
            )
            
            return result.returncode == 0
            
        except Exception as e:
            logger.error(f"修复NTP服务失败: {e}")
            return False

def demo_basic_usage():
    """基础使用演示"""
    print("=== RTC时间管理基础演示 ===")
    
    # 创建RTC管理器
    rtc = RTCManager()
    
    # 检查RTC设备
    if not rtc.rtc_devices:
        print("未检测到RTC设备")
        return
    
    print(f"检测到RTC设备: {list(rtc.rtc_devices.keys())}")
    
    # 读取RTC信息
    print("\n1. 读取RTC设备信息:")
    rtc_info = rtc.read_rtc_info()
    if rtc_info:
        print(f"  设备: {rtc_info.device}")
        print(f"  名称: {rtc_info.name}")
        print(f"  日期: {rtc_info.date}")
        print(f"  时间: {rtc_info.time}")
        print(f"  Epoch秒数: {rtc_info.since_epoch}")
        print(f"  完整时间: {rtc_info.datetime_obj}")
    
    # 读取/proc/driver/rtc信息
    print("\n2. 读取详细RTC信息:")
    proc_rtc = rtc.read_proc_rtc()
    if proc_rtc:
        for key, value in proc_rtc.items():
            print(f"  {key}: {value}")
    
    # 比较时间
    print("\n3. 比较系统时间和RTC时间:")
    comparison = rtc.compare_times()
    if comparison:
        print(f"  系统时间: {comparison.system_time}")
        print(f"  RTC时间: {comparison.rtc_time}")
        print(f"  时间差异: {comparison.difference_seconds:.2f}秒")
        print(f"  RTC更快: {comparison.rtc_faster}")
        print(f"  需要同步: {comparison.sync_needed}")

def demo_time_sync():
    """时间同步演示"""
    print("\n=== 时间同步演示 ===")
    
    rtc = RTCManager()
    
    # 显示当前时间状态
    print("当前时间状态:")
    comparison = rtc.compare_times()
    if comparison:
        print(f"  系统时间: {comparison.system_time.strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"  RTC时间: {comparison.rtc_time.strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"  时间差异: {comparison.difference_seconds:.2f}秒")
        
        if comparison.sync_needed:
            print(f"  时间差异超过阈值({rtc.sync_threshold}秒)，建议同步")
            
            choice = input("选择同步方向 (1=系统->RTC, 2=RTC->系统, 3=自动): ").strip()
            
            if choice == "1":
                success = rtc.sync_system_to_rtc()
                print(f"同步结果: {'成功' if success else '失败'}")
            elif choice == "2":
                success = rtc.sync_rtc_to_system()
                print(f"同步结果: {'成功' if success else '失败'}")
            elif choice == "3":
                success = rtc.auto_sync()
                print(f"自动同步结果: {'成功' if success else '失败'}")
        else:
            print("  时间差异在允许范围内，无需同步")
    
    # 再次检查时间
    print("\n同步后时间状态:")
    comparison = rtc.compare_times()
    if comparison:
        print(f"  系统时间: {comparison.system_time.strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"  RTC时间: {comparison.rtc_time.strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"  时间差异: {comparison.difference_seconds:.2f}秒")

def demo_time_monitoring():
    """时间监控演示"""
    print("\n=== 时间监控演示 ===")
    
    rtc = RTCManager()
    
    print("开始时间漂移监控...")
    print("监控将持续5分钟,每30秒检查一次")
    print("按Ctrl+C提前停止监控")
    
    try:
        rtc.monitor_time_drift(duration_minutes=5, check_interval=30)
    except KeyboardInterrupt:
        print("\n监控被用户中断")

def demo_manual_operations():
    """手动操作演示"""
    print("\n=== 手动操作演示 ===")
    
    rtc = RTCManager()
    
    while True:
        print("\n选择操作:")
        print("1. 查看RTC时间")
        print("2. 查看系统时间")
        print("3. 比较时间")
        print("4. 系统时间 -> RTC")
        print("5. RTC时间 -> 系统")
        print("6. 自动同步")
        print("7. 导出信息")
        print("8. 退出")
        
        choice = input("请选择 (1-8): ").strip()
        
        if choice == "1":
            rtc_time = rtc.read_hwclock()
            if rtc_time:
                print(f"RTC时间: {rtc_time.strftime('%Y-%m-%d %H:%M:%S')}")
            else:
                print("读取RTC时间失败")
        
        elif choice == "2":
            system_time = datetime.now()
            print(f"系统时间: {system_time.strftime('%Y-%m-%d %H:%M:%S')}")
        
        elif choice == "3":
            comparison = rtc.compare_times()
            if comparison:
                print(f"系统时间: {comparison.system_time.strftime('%Y-%m-%d %H:%M:%S')}")
                print(f"RTC时间: {comparison.rtc_time.strftime('%Y-%m-%d %H:%M:%S')}")
                print(f"时间差异: {comparison.difference_seconds:.2f}秒")
                print(f"需要同步: {comparison.sync_needed}")
            else:
                print("比较时间失败")
        
        elif choice == "4":
            success = rtc.sync_system_to_rtc()
            print(f"同步结果: {'成功' if success else '失败'}")
        
        elif choice == "5":
            success = rtc.sync_rtc_to_system()
            print(f"同步结果: {'成功' if success else '失败'}")
        
        elif choice == "6":
            success = rtc.auto_sync()
            print(f"自动同步结果: {'成功' if success else '失败'}")
        
        elif choice == "7":
            rtc.export_rtc_info()
            print("RTC信息已导出")
        
        elif choice == "8":
            break
        
        else:
            print("无效选择")
